﻿using Dapper;
using System.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;
using YAKEJI.Abp.Database;
using YAPACS.Organizations;
using YAPACS.RisServer.Abstractions;
using YAPACS.RisServer.Interface.Imitate;
using YAPACS.RisServer.Services.ECharts;

namespace YAPACS.RisServer.Services;

public class HomeChartService(IEChartFactoryService eChartFactoryService,
                               ICurrentUser currentUser,
                               ICurrentUserOrganization _userOrganization,
                               IConfiguration _configuration,
                               ICommonUse commonUse,
                               IChartService chartService
                               ) : IHomeChartService, ITransientDependency
{
    private readonly IEChartFactoryService _eChartFactoryService = eChartFactoryService;
    private readonly ICurrentUser _currentUser = currentUser;
    private readonly ICurrentUserOrganization userOrganization = _userOrganization;
    private readonly IConfiguration configuration = _configuration;
    private readonly ICommonUse _commonUse = commonUse;
    private readonly IChartService _chartService = chartService;


    #region 主方法_工作量图表配置
    /// <summary>
    /// 获取图表配置
    /// </summary>
    /// <param name="position">流程位置</param>
    /// <param name="level">主体层级</param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public AmisRes GetWorkloadChartOption(string stage, string level, DateTime startTime, DateTime endTime, string granularity, string stationCode)
    {
        AmisRes res = new AmisRes();

        try
        {
            if (!string.IsNullOrEmpty(stage) && !string.IsNullOrEmpty(level) && !string.IsNullOrEmpty(granularity))
            {
                EChart chart = _eChartFactoryService.GetNewChart();
                chart.DataSet = _eChartFactoryService.GetNewDataSourceList();
                endTime = endTime.AddHours(23).AddMinutes(59).AddSeconds(59);
                chart.DataSet.Add(GetWorkLoadDataSet(stage, level, startTime, endTime, granularity, "工作量", stationCode));
                chart.Legend = null;

                // x轴
                chart.XAxis = _eChartFactoryService.GetNewAxisList();
                var axis = _eChartFactoryService.GetNewAxis();
                axis.Type = "category";
                string labelFormat = "";
                switch (granularity)
                {
                    case "Month":
                        labelFormat = "{value}";
                        axis.Name = "月次";
                        break;

                    case "Week":
                        labelFormat = "{value}周";
                        axis.Name = "周次";
                        break;

                    case "Day":
                        labelFormat = "{value}";
                        axis.Name = "日期";
                        break;

                    default:
                        break;
                }
                axis.AxisLabel = new
                {
                    Formatter = labelFormat,
                    Align = "center"
                }; // 轴标签
                chart.XAxis.Add(axis);


                // y轴
                chart.YAxis = _eChartFactoryService.GetNewAxisList();
                var axis2 = _eChartFactoryService.GetNewAxis();
                axis2.Type = "value"; // 轴类型
                axis2.Name = "工作量";
                chart.YAxis.Add(axis2);

                // 系列
                chart.Series = _eChartFactoryService.GetNewSeriesList();
                var series = _eChartFactoryService.GetNewSeriesItem();

                chart.Series.Add(series);
                res.Data = chart.GetSchema();

            }
            else
            {
                res.Status = 1;
                res.Msg = "输入参数有误，无法获取图表配置！";
            }
            return res;
        }
        catch (Exception ex)
        {
            res.Msg = ex.Message;
            res.Status = 1;
            return res;
        }
    }
    #endregion


    #region 获取工作量图表数据集
    /// <summary>
    /// 获取工作量数据集(单个数据集)
    /// </summary>
    /// <param name="stage"></param>
    /// <param name="level"></param>
    /// <param name="startTime"></param>
    /// <param name="endTime"></param>
    /// <param name="granularity"></param>
    /// <returns></returns>
    public DataSource GetWorkLoadDataSet(string stage, string level, DateTime startTime, DateTime endTime, string granularity, string seriesName, string stationCode)
    {
        DatabaseType databaseType;
        using (var connection = _commonUse.GetDapperConnection(out databaseType))
        {
            DataSource dataSource = null;
            List<Category> categories = null;
            DynamicParameters parameters = new DynamicParameters();
            parameters.Add("@UserId", _currentUser.Id.ToString());
            parameters.Add("@DepartmentId", userOrganization.DepartmentId.ToString());
            parameters.Add("@EndTime", endTime);
            parameters.Add("@StartTime", startTime);
            if (!string.IsNullOrEmpty(stationCode))
            {
                parameters.Add("@StationCode", stationCode);
            }

            // 类目计算
            switch (granularity)
            {
                case "Month":
                    categories = _chartService.GetMonthsBetween(startTime, endTime);
                    break;

                case "Week":
                    categories = _chartService.GetWeeksBetween(startTime, endTime);
                    break;

                case "Day":
                    categories = _chartService.GetDaysBetween(startTime, endTime);
                    break;

                default:
                    break;
            }

            // 检查阶段
            switch (stage)
            {
                case "Register": //　登记
                    dataSource = GetExamData(level, granularity, seriesName, parameters, categories, connection, databaseType, "RegisterTime", "CreatorId", "");
                    break;

                case "Exam":  // 检查
                    dataSource = GetExamData(level, granularity, seriesName, parameters, categories, connection, databaseType, "ExamTime", "ExamOperator", "0,1,2");
                    break;

                case "Report": // 报告
                    dataSource = GetReportData(level, granularity, seriesName, parameters, categories, connection, databaseType, "ReportTime", "ReportDoctor", "0,1,2");
                    break;

                case "Audit": // 审核
                    dataSource = GetReportData(level, granularity, seriesName, parameters, categories, connection, databaseType, "AuditTime", "AuditDoctor", "0,1,2,3,4");
                    break;

                case "Review": // 复审
                    dataSource = GetReportData(level, granularity, seriesName, parameters, categories, connection, databaseType, "ReviewTime", "ReviewDoctor", "0,1,2,3,4,5,6");
                    break;

                default:
                    break;
            }
            return dataSource;
        }
    }
    #endregion


    #region 登记阶段工作量统计
    /// <summary>
    /// 登记阶段工作量统计
    /// </summary>
    /// <param name="level">主体级别</param>
    /// <param name="startTime">开始时间</param>
    /// <param name="endTime">结束时间</param>
    /// <param name="granularity">显示粒度</param>
    /// <returns></returns>
    public DataSource GetExamData(string level, string granularity, string seriesName, DynamicParameters parameters, List<Category> categories, IDbConnection connection, DatabaseType databaseType, string timeField, string userField, string statuNotIn)
    {
        DataSource dataSource = _eChartFactoryService.GetNewDataSource();
        string nameColumn = "";
        string tableName = "Exam";
        string levelCondition = "";
        string notIn = "";
        if (timeField != "RegisterTime")
        {
            notIn = $" And ExamStatus not in ({statuNotIn})";
        }

        // 主体层级条件
        switch (level)
        {
            case "User": //  用户
                levelCondition = $"{userField} = @UserId";
                break;

            case "Station": // 站点
                levelCondition = @"ExamDevice 
			                       in  
			                       ( select Oid from Device where Station 
					                    in 
					                 (select Oid from Station  where Code = @StationCode)
			                        ) ";
                break;

            case "Department": // 科室
                levelCondition = "Department = @DepartmentID";
                break;

            default:
                break;
        }

        // 分组条件(Name 列名)
        if (databaseType == DatabaseType.MySql)
        {
            switch (granularity)
            {
                case "Day":
                    nameColumn = $"DATE_FORMAT({timeField},'%m-%d')";
                    break;

                case "Week":
                    nameColumn = $@" CONCAT(YEAR({timeField}),
                                       '-',
                                   LPAD(WEEK({timeField},1), 2, '0'))";

                    break;

                case "Month":
                    nameColumn = $"DATE_Format({timeField},'%Y-%m')";
                    break;

                default:
                    break;
            }
        }
        else // sqlServer
        {
            switch (granularity)
            {
                case "Day":
                    nameColumn = $"FORMAT({timeField},'MM-dd')";
                    break;

                case "Week":
                    nameColumn = "CONCAT(CAST(DATEPART(YEAR, D.Thursday) AS VARCHAR(4)), '-', RIGHT('0' + CAST(DATEPART(WEEK, D.Thursday) AS VARCHAR(2)), 2))";
                    tableName += $"\n CROSS APPLY(VALUES(CAST(DATEADD(DAY, (DATEDIFF(DAY, 0, {timeField}) / 7) * 7, 3) AS DATE))) AS D(Thursday)";
                    break;

                case "Month":
                    nameColumn = $"Format({timeField},'yyyy-MM')";
                    break;

                default:
                    break;
            }
        }

        string sqlStr = $@"SELECT 
                                     {nameColumn} AS Name,
                                      COUNT(*) AS Count
                                FROM 
                                    {tableName} 
                                WHERE 
                                    {levelCondition}
                                    and 
                                    {timeField} < @EndTime
                                    and 
                                    {timeField} >= @StartTime 
                                    {notIn}
                                GROUP BY 
                                     {nameColumn}
                           ";

        dataSource.Source = _chartService.FillDataSource(connection, parameters, categories, sqlStr, seriesName, dataSource.Source);
        return dataSource;
    }
    #endregion


    #region 报告阶段工作量统计(主)
    /// <summary>
    /// 报告阶段工作量统计
    /// </summary>
    /// <param name="level">主体层级</param>
    /// <param name="startTime">开始时间</param>
    /// <param name="endTime">结束时间</param>
    /// <param name="granularity">统计粒度</param>
    /// <returns></returns>
    public DataSource GetReportData(string level, string granularity, string seriesName, DynamicParameters parameters, List<Category> categories, IDbConnection connection, DatabaseType databaseType, string timeField, string userField, string statusNotIn)
    {
        DataSource dataSource = _eChartFactoryService.GetNewDataSource();
        string nameColumn = "";
        string tableName = "Report";
        string levelCondition = "";

        switch (level)
        {
            case "User": // 用户
                levelCondition = $"{userField} = @UserId";
                break;

            case "Station":// 站点
                levelCondition = @"Exam in (select Oid from Exam where ExamDevice 
						                        in
						                        (select Oid from Device where Station 
							                        =
							                        (
								                        select Oid from Station where Code =@StationCode
							                        )
						                        )
					                ) ";
                break;

            case "Department":// 科室
                levelCondition = @" Exam 
			                        in 
			                        (
				                        select Oid from Exam where Department =  @DepartmentId
			                        )";
                break;

            default:
                break;
        }

        // 分组条件(Name 列名)
        if (databaseType == DatabaseType.MySql)
        {
            switch (granularity)
            {
                case "Day":
                    nameColumn = $"DATE_FORMAT({timeField},'%m-%d')";
                    break;

                case "Week":
                    nameColumn = $@"CONCAT(YEAR({timeField}),
                                       '-',
                                   LPAD(WEEK({timeField},1), 2, '0'))";
                    break;

                case "Month":
                    nameColumn = $"DATE_FORMAT({timeField},'%Y-%m')";
                    break;

                default:
                    break;
            }
        }
        else // sqlServer
        {
            switch (granularity)
            {
                case "Day":
                    nameColumn = $"FORMAT({timeField},'MM-dd')";
                    break;

                case "Week":
                    nameColumn = @"Exam 
			                        in 
			                        (
				                        select Oid from Exam where Department =  @DepartmentId
			                        )";
                    tableName += $" \n CROSS APPLY(VALUES(CAST(DATEADD(DAY, (DATEDIFF(DAY, 0, {timeField}) / 7) * 7, 3) AS DATE))) AS D(Thursday)";
                    break;

                case "Month":
                    nameColumn = $"Format({timeField},'yyyy-MM')";
                    break;

                default:
                    break;
            }
        }

        string sqlStr = $@"SELECT 
			                    {nameColumn} AS Name,
			                    COUNT(*) AS 'Count'
		                    FROM 
			                    {tableName}
		                    WHERE 
			                    {levelCondition}
			                    AND
			                    {timeField} <= @EndTime
			                    AND
			                    {timeField} >= @StartTime
		                        AND 
			                    ReportStatus  not in ({statusNotIn})
		                    GROUP BY 
			                    {nameColumn}";

        dataSource.Source = _chartService.FillDataSource(connection, parameters, categories, sqlStr, seriesName, dataSource.Source);
        return dataSource;
    }
    #endregion
}
